<!--
 * @Description: 
 * @Author: Cxy
 * @Date: 2024-12-26 19:49:28
 * @LastEditors: Cxy
 * @LastEditTime: 2025-09-23 23:04:58
 * @FilePath: \xy-admin\play\src\views\components\table.vue
-->
<script setup lang="ts">
import { XyTable } from '@xy-admin/elecomponents'
import { ElButton } from 'element-plus'
import XyIcon, { XyIconRender } from '@/components/XyIcon'
enum Type {
  Default = 'default'
}
interface Student {
  id: number
  name: string
  age: number
  sex: string
  address: string
  banji: string
  expand: any[]
}
const generalColumns = [
  {
    type: Type.Default,
    label: '姓名',
    prop: 'name'
  },
  {
    type: Type.Default,
    label: '年龄',
    prop: 'age'
  },
  { type: Type.Default, label: '性别', prop: 'sex' },
  { type: Type.Default, label: '地址', prop: 'address' }
]
const tableData = reactive<any[]>([
  {
    id: 1,
    name: '王五',
    age: 20,
    sex: '男',
    address: '北京市',
    banji: '1班',
    expand: []
  },
  {
    id: 2,
    name: '张三',
    age: 18,
    sex: '',
    address: '开鲁县',
    banji: '2班',
    expand: []
  },
  {
    id: 3,
    name: '李四',
    age: 19,
    sex: '男',
    address: '通辽市',
    banji: '',
    expand: []
  }
])
const tableConfig = reactive<TableConfig<Student>>({
  columns: [
    {
      type: 'expand',
      prop: 'expand',
      defaultCell: props => {
        return h(XyTable, {
          tableConfig: { columns: generalColumns },
          tableData: props.row.expand
        })
      }
    },
    {
      label: '序号',
      type: 'index',
      prop: 'index'
    },
    ...generalColumns
  ],
  highlightCurrentRow: true,
  rowKey: 'id',
  expandRowKeys: [1],
  rowClick(row) {
    console.log(row)
    tableConfig.expandRowKeys = [1, 2, 3]
  },
  rowDblclick(row) {
    console.log(row)
  },
  async expandChange(row) {
    await new Promise(r => setTimeout(r, 5000))
    row.expand.push({
      name: '我是异步插入的数据',
      age: 18,
      sex: '女',
      address: '通辽市',
      id: Date.now()
    })
  }
})
const tableRef = useTemplateRef('tableRef')
onMounted(async () => {
  const a = await tableRef.value?.getTableRef?.()
  a?.setCurrentRow(tableData[2])
  console.log(a)
  const b = await tableRef.value?.getFormRef?.()
  console.log(b)
})
const tableConfigSpan = reactive<TableConfig>({
  columns: [
    {
      type: 'default',
      label: '姓名',
      prop: 'name',
      rowSpan: idx => {
        if (idx === 0) return 2
      }
    },
    {
      type: 'default',
      label: '年龄',
      prop: 'age',
      colSpan: idx => {
        return idx === 0 ? 3 : 1
      }
    },
    {
      type: 'default',
      label: '性别',
      prop: 'sex',
      colSpan: idx => {
        if (idx === 0) return 3
        if (idx === 1) return 2
      }
    },
    { type: 'default', label: '地址', prop: 'address' }
  ]
})
const tableConfigRadio = reactive<TableConfig<Student>>({
  columns: [
    {
      type: 'single',
      prop: 'single',
      selectable(_, index) {
        return index !== 0
      }
    },
    ...generalColumns
  ],
  singleChange(data) {
    console.log(data)
  }
})
const tableRadioRef = useTemplateRef('tableRadioRef')
const toggleRowRadio = () => {
  if (tableRadioRef.value) {
    tableRadioRef.value.tableRef?.toggleRowRadio(tableData[0], undefined, true)
  }
}
const singleChange = (data: Student) => {
  console.log(data)
}
const tableConfigSelection = reactive<TableConfig<Student>>({
  columns: [
    {
      type: 'selection',
      prop: 'selection',
      selectable(row) {
        return row.name !== '张三'
      }
    },
    ...generalColumns
  ],
  select(data, row) {
    console.log(data, row)
  },
  selectAll(data) {
    console.log(data)
  },
  selectionChange(data) {
    console.log(data)
  }
})
const tableConfigSlot = reactive<TableConfig<Student>>({
  columns: [
    {
      type: 'expand',
      prop: 'expand'
    },
    {
      label: '序号',
      type: 'index',
      prop: 'index',
      headerCell: props => {
        return h('div', { style: { color: 'red' } }, props.column.label)
      },
      defaultCell: props => {
        return h('div', { style: { color: 'red' } }, props.$index + 2)
      }
    },
    { type: 'default', label: '姓名', prop: 'name' },
    { type: 'default', label: '年龄', prop: 'age', slotName: 'age123' },
    {
      type: 'default',
      label: '性别',
      prop: 'sex',
      defaultCell: props => {
        return props.row.sex
          ? h(
              ElTag,
              {
                type: props.row.sex === '男' ? 'success' : 'warning',
                effect: 'plain',
                onClick: () => {
                  console.log(props.row)
                }
              },
              () => props.row.sex
            )
          : ''
      }
    },
    { type: 'default', label: '地址', prop: 'address', slotName: 'address' }
  ]
})
const tableConfigSort = reactive<TableConfig<Student>>({
  columns: [
    { type: 'default', label: '姓名（前端）', prop: 'name', sortable: true },
    {
      type: 'default',
      label: '年龄（前端）',
      prop: 'age',
      propAlias: 'ageAlias',
      sortable: true,
      sortOrders: ['descending', 'ascending', 'none'],
      sortOper: (a, b, sortKey) => {
        if (sortKey === 'descending') return b.age - a.age
        return a.age - b.age
      }
    },
    {
      type: 'default',
      label: '性别（后端）',
      prop: 'sex',
      propAlias: 'sex123',
      sortable: 'searchMethod',
      sortIcon: () => h(XyIcon, { style: { fontSize: '16px' }, icon: 'tabler:sort-descending-2-filled' })
    }
  ]
})
const tableSortRef = useTemplateRef('tableSortRef')
const clearSortSex = () => {
  tableSortRef.value?.tableRef?.sortClearCondition?.('sex')
}
const clearSortAge = () => {
  tableSortRef.value?.tableRef?.sortClearCondition?.('age')
}
const clearSortAll = () => {
  tableSortRef.value?.tableRef?.sortClearCondition?.()
}
const tableConfigFilter = reactive<TableConfig>({
  columns: [
    {
      type: 'default',
      label: '姓名（单选）',
      prop: 'name',
      filterType: 'radio',
      filterData: [
        { label: '张三', value: '张三' },
        { label: '李四', value: '李四' },
        { label: '王五', value: '王五' }
      ]
    },
    {
      type: 'default',
      label: '年龄（多选）',
      prop: 'age',
      filterType: 'checkbox',
      filterData: [
        { label: '18', value: 18 },
        { label: '19', value: 19 },
        { label: '20', value: 20 }
      ],
      filterOper(value, row) {
        return row.age === value
      },
      filterIcon: () => h(XyIcon, { icon: 'tabler:filter-search' })
    },
    {
      type: 'default',
      label: '性别（下拉）',
      prop: 'sex',
      propAlias: 'sex123',
      filterType: 'select',
      filterData: [
        { label: '男', value: '男' },
        { label: '女', value: '女' }
      ],
      filterOper(value, row) {
        return row.sex === value
      },
      filterIcon: () => h(XyIcon, { icon: 'mdi:account-filter-outline' })
    },
    {
      type: 'default',
      label: '班级（输入框）',
      prop: 'banji',
      filterType: 'input',
      filterOper(value, row) {
        return row.banji?.includes(String(value))
      },
      filterIcon: () => h(XyIcon, { icon: 'mdi:account-filter-outline' })
    },
    {
      type: 'default',
      label: '地址（后端）',
      prop: 'address',
      propAlias: 'address123',
      filterType: 'checkbox.searchMethod',
      filterData: [
        { label: '北京市', value: '北京市' },
        { label: '通辽市', value: '通辽市' },
        { label: '开鲁县', value: '开鲁县' }
      ],
      filterIcon: () => h(XyIcon, { icon: 'mdi:account-filter-outline' })
    }
  ],
  loadingConf: {
    target: '#watermark',
    text: '哈哈哈哈...',
    svg: `<g fill="none" stroke="var(--el-color-primary)" strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}><path d="M3 12a9 9 0 0 0 9 9a9 9 0 0 0 9-9a9 9 0 0 0-9-9"></path><path d="M17 12a5 5 0 1 0-5 5"></path></g>`,
    svgViewBox: '0 0 24 24'
  },
  pageConf: {
    prevText: '上一页',
    nextText: '下一页',
    pageSizes: [10, 20, 30],
    pageSize: 20,
    total: 61,
    currentPage: 3
  },
  stripe: true,
  searchMethod() {}
})
const tableFilterRef = useTemplateRef('tableFilterRef')
const clearFilterName = () => {
  tableFilterRef.value?.tableRef?.filterClearCondition?.('name', 'sex123')
}
const clearFilterAll = () => {
  tableFilterRef.value?.tableRef?.filterClearCondition?.()
}
const searchMethod = async (searchData: SearchData, pageData: PageData) => {
  pageData.loading = true
  console.log(searchData)
  await new Promise(r => setTimeout(r, 500))
  tableData.push({
    name: '我是排序',
    age: 18,
    sex: '女',
    address: '通辽市'
  })
  pageData.loading = false
  pageData.total = 100
  pageData.tableData = tableData
}
const tableConfigMultiHeader = reactive<TableConfig>({
  columns: [{ type: 'default', label: '基本信息', children: generalColumns, prop: 'baseInfo' }]
})
const EditIpt = defineComponent({
  name: 'EditIpt',
  props: {
    value: {
      type: [Number, String]
    }
  },
  emits: ['changeValue'],
  setup(props, { emit }) {
    const isEdit = ref(false)
    const inputRef = useTemplateRef('inputRef') as Ref<HTMLInputElement>
    async function handleOnClick() {
      isEdit.value = true
      await nextTick()
      inputRef.value?.focus()
    }
    return () =>
      h(
        'div',
        {
          onClick: handleOnClick
        },
        [
          isEdit.value
            ? h(ElInput, {
                ref: 'inputRef',
                modelValue: props.value,
                onInput(v) {
                  emit('changeValue', v)
                },
                onBlur() {
                  isEdit.value = false
                }
              })
            : props.value
        ]
      )
  }
})
const tableEditRef = useTemplateRef('tableEditRef')
const tableConfigEdit = reactive<TableConfig<Student>>({
  columns: [
    {
      type: 'default',
      label: '姓名',
      prop: 'name',
      defaultCell(props) {
        return h(ElInput, {
          modelValue: props.row.name,
          onInput(v) {
            props.row.name = v
          }
        })
      }
    },
    {
      type: 'default',
      label: '年龄',
      prop: 'age',
      defaultCell(props) {
        return h(EditIpt, {
          value: props.row.age,
          onChangeValue(v: number) {
            props.row.age = v
          }
        })
      }
    },
    {
      label: '班级',
      prop: 'banji',
      type: 'input',
      isShow: true,
      rule: [
        {
          required: true,
          trigger: 'blur'
        },
        { min: 3, max: 5, message: '长度 3 到 5', trigger: 'blur' }
      ]
    },
    {
      label: '性别',
      prop: 'sex',
      type: 'radio.button',
      rule: [
        {
          required: true,
          trigger: 'change'
        }
      ],
      data: [
        {
          label: '男',
          value: '男'
        },
        {
          label: '女',
          value: '女'
        }
      ]
    },
    {
      label: '地址',
      prop: 'address',
      type: 'select',
      data: [
        { label: '北京', value: 'beijing' },
        { label: '上海', value: 'shanghai' },
        { label: '广州', value: 'guangzhou' }
      ]
    },
    {
      label: '年月日',
      prop: 'date',
      type: 'date',
      rule: [
        {
          required: true,
          message: '请选择日期',
          trigger: 'change'
        }
      ]
    },
    {
      label: '操作',
      type: 'operate',
      prop: 'operate',
      width: 230,
      buttons: props => [
        {
          label: '提交',
          isShow: props.row.age < 19,
          text: true,
          click: async props => {
            const tableData = await tableEditRef.value?.tableRef?.validate?.({ rows: props.$index })
            console.log(tableData)
          }
        },
        {
          label: '删除',
          type: 'primary',
          click: props => {
            console.log(props)
          }
        }
      ]
    }
  ]
})
const editValidate = async () => {
  const tableData = await tableEditRef.value?.tableRef?.validate?.({ rows: [1, 2] })
  console.log(tableData)
}

const tableConfigOper = reactive<TableConfig>({
  columns: [
    {
      label: '地址',
      prop: 'address',
      type: 'select',
      data: [
        { label: '北京', value: 'beijing' },
        { label: '上海', value: 'shanghai' },
        { label: '广州', value: 'guangzhou' }
      ]
    },
    {
      label: '操作',
      type: 'operate',
      prop: 'operate',
      width: 300,
      buttons: props => [
        {
          label: '编辑',
          isShow: props.row.age < 19,
          click: async props => {
            props.button.loading = true
            await new Promise(resolve => setTimeout(resolve, 2000))
            props.button.loading = false
          },
          loading: false,
          icon: h(XyIcon, { icon: 'fluent:people-edit-16-filled' })
        },
        {
          label: '删除',
          type: 'primary',
          click: props => {
            console.log(props)
          }
        },
        {
          label: '详情',
          click: (props: any) => {
            console.log(props)
          }
        },
        {
          label: '不传插槽名',
          type: 'success'
        },
        {
          label: '函数渲染',
          type: 'success',
          btnVNode(props) {
            return h(ElButton, { type: props.button.type, onClick: () => console.log(props) }, () => '函数渲染')
          }
        },
        {
          label: '传插槽名',
          type: 'danger',
          slotName: 'slotName'
        }
      ]
    },
    {
      label: '操作（自定义）',
      type: 'operate',
      prop: 'operate2',
      minWidth: 140,
      slotName: 'operate'
    }
  ]
})
const tableConfigButton = reactive<TableConfig>({
  isSearchMethod: false,
  columns: [
    {
      type: 'single',
      prop: 'single',
      selectable(_, index) {
        return index !== 0
      }
    },
    {
      type: 'selection',
      prop: 'selection'
    },
    {
      type: 'default',
      label: '年龄1',
      prop: 'age1',
      minWidth: 300
    },
    ...generalColumns,
    {
      type: 'default',
      label: '地址（后端）',
      prop: 'address',
      width: 300,
      propAlias: 'address123',
      filterType: 'checkbox.searchMethod',
      filterData: [
        { label: '北京市', value: '北京市' },
        { label: '通辽市', value: '通辽市' },
        { label: '开鲁县', value: '开鲁县' }
      ],
      filterIcon: () => h(XyIcon, { icon: 'mdi:account-filter-outline' })
    },
    {
      type: 'default',
      label: '年龄2',
      prop: 'age2',
      minWidth: 800
    },
    {
      type: 'default',
      label: '年龄3',
      prop: 'age3',
      minWidth: 800
    }
  ],
  buttonTopOperateConf: [
    {
      buttonPosition: 'left',
      slotName: 'search'
    },
    {
      label: '增加',
      type: 'primary',
      buttonPosition: 'left',
      icon: shallowRef(XyIconRender('line-md:plus-square')),
      click: data => {
        console.log(data)
      },
      isSecondConfirm: true,
      title: '确定要增加吗？'
    },
    {
      type: 'danger',
      buttonPosition: 'left',
      icon: shallowRef(XyIconRender('line-md:document-delete')),
      click: data => {
        console.log(data)
      }
    },
    {
      buttonPosition: 'left',
      label: '筛选'
    },
    {
      buttonPosition: 'right',
      btnVNode(props) {
        return h(ElButton, { onClick: () => console.log(props) }, () => '导出')
      }
    },
    {
      circle: true,
      type: 'danger',
      buttonPosition: 'right',
      actionType: 'refresh'
    },
    {
      label: '表格操作',
      type: 'danger',
      buttonPosition: 'right',
      actionType: 'columnAction',
      columnActionConfirm: true,
      columnActionMethod(columnActionData) {
        console.log(columnActionData)
      }
    }
  ],
  columnActionData: [
    {
      type: 'single',
      columnSH: true,
      prop: 'single',
      fixed: 'left'
    },
    {
      type: 'selection',
      columnSH: false,
      prop: 'selection'
    },
    {
      prop: 'name',
      type: 'default',
      label: '姓名',
      columnSH: false
    },
    {
      prop: 'age',
      type: 'default',
      label: '年龄',
      columnSH: false
    },
    {
      prop: 'sex',
      type: 'default',
      label: '性别',
      columnSH: false
    },
    {
      prop: 'address',
      type: 'default',
      label: '地址',
      columnSH: true
    },
    {
      prop: 'age2',
      type: 'default',
      label: '年龄2',
      columnSH: true
    },
    {
      prop: 'age3',
      type: 'default',
      label: '年龄3',
      columnSH: true
    },
    {
      prop: 'age1',
      type: 'default',
      label: '年龄1',
      columnSH: true
    }
  ]
})
const columnActionMethod = (val: any) => {
  console.log(val)
}
const select = ref('')
const search = ref('')
</script>
<template>
  <div>
    <h3>展开行、多选、序号、单机行、双击行</h3>
    <XyTable ref="tableRef" :tableConfig="tableConfig" :tableData="tableData">
      <template #append>
        <h3>表格最后一行，不用可不加</h3>
      </template>
    </XyTable>
    <h3>行列合并</h3>
    <XyTable :tableConfig="tableConfigSpan" :tableData="tableData" />
    <h3>单选 <ElButton @click="toggleRowRadio">设置第一行</ElButton></h3>
    <XyTable ref="tableRadioRef" :tableConfig="tableConfigRadio" :tableData="tableData" @single-change="singleChange" />
    <h3>多选</h3>
    <XyTable :tableConfig="tableConfigSelection" :tableData="tableData" />
    <h3>插槽</h3>
    <XyTable :tableConfig="tableConfigSlot" :tableData="tableData">
      <template #nameHeader="{ column }">
        <em style="color: blueviolet">{{ column.label }}</em>
      </template>
      <template #name="{ row }">
        <span style="color: blueviolet">{{ row.name }}</span>
      </template>
      <template #expand="{ row }">
        <div>{{ row.name }}</div>
      </template>
      <template #age123="scope">
        <div @click="console.log(scope)">{{ scope.row.age }}啊啊</div>
      </template>
      <template #addressHeader="scope">
        <div style="color: blueviolet" @click="console.log(scope)">{{ scope.column.label }}</div>
      </template>
    </XyTable>
    <h3>
      排序
      <ElButton @click="clearSortSex">清空性别排序</ElButton>
      <ElButton @click="clearSortAge">清空年龄排序</ElButton>
      <ElButton @click="clearSortAll">清空全部排序</ElButton>
    </h3>
    <XyTable ref="tableSortRef" :tableConfig="tableConfigSort" :tableData="tableData" @search-method="searchMethod" />
    <h3>
      过滤
      <ElButton @click="clearFilterName">清空姓名、性别筛选项</ElButton>
      <ElButton @click="clearFilterAll">清空全部筛选项</ElButton>
    </h3>
    <XyTable
      ref="tableFilterRef"
      :tableConfig="tableConfigFilter"
      :tableData="tableData"
      @search-method="searchMethod"
    />
    <h3>多级表头</h3>
    <XyTable :tableConfig="tableConfigMultiHeader" :tableData="tableData" />
    <h3>
      表格编辑（直接展示和只展示一个）
      <ElButton @click="editValidate">校验第二行和第三行</ElButton>
    </h3>
    <XyTable ref="tableEditRef" :tableConfig="tableConfigEdit" :tableData="tableData">
      <template #data="prop">
        {{ prop.row.data || '\u200B' }}
      </template>
    </XyTable>
    <h3>操作列</h3>
    <XyTable :tableConfig="tableConfigOper" :tableData="tableData">
      <template #不传插槽名="data">
        <el-button :type="data.button.type" @click="console.log(data)">不传插槽名</el-button>
      </template>
      <template #slotName="data">
        <el-button :type="data.button.type" text @click="console.log(data)">传插槽名</el-button>
      </template>
      <template #operate="data">
        <span @click="console.log(data)">操作</span>
      </template>
    </XyTable>
    <h3>表格顶部按钮</h3>
    <XyTable :tableData="tableData" :tableConfig="tableConfigButton" @column-action-method="columnActionMethod">
      <template #筛选="scope">
        <span>{{ scope }}</span>
      </template>
      <template #search="scope">
        <el-input v-model="search" placeholder="Please input" style="margin-right: 12px">
          <template #prepend>
            <el-select v-model="select" placeholder="Select" style="width: 115px">
              <el-option label="Restaurant" value="1" />
              <el-option label="Order No." value="2" />
              <el-option label="Tel" value="3" />
            </el-select>
          </template>
          <template #append>
            <el-button :icon="XyIconRender('mdi:magnify')" type="primary" @click="console.log(scope)" />
          </template>
        </el-input>
      </template>
    </XyTable>
  </div>
</template>
<style lang="scss" scoped>
h3 {
  margin: 10px 0;
}
</style>
